import { parseTime } from "./utils";

/**
 * 表格时间格式化
 */
export function formatDate(cellValue: any) {
	if (cellValue == null || cellValue == "") return "";
	let date = new Date(cellValue);
	let year = date.getFullYear();
	let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
	let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
	let hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
	let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
	let seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
	return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
}

/**
 * @param {number} time
 * @param {string} option
 * @returns {string}
 */
export function formatTime(time: any, option: any) {
	if (("" + time).length === 10) {
		time = parseInt(time) * 1000;
	} else {
		time = +time;
	}
	const d: any = new Date(time);
	const now = Date.now();

	const diff = (now - d) / 1000;

	if (diff < 30) {
		return "刚刚";
	} else if (diff < 3600) {
		// less 1 hour
		return Math.ceil(diff / 60) + "分钟前";
	} else if (diff < 3600 * 24) {
		return Math.ceil(diff / 3600) + "小时前";
	} else if (diff < 3600 * 24 * 2) {
		return "1天前";
	}
	if (option) {
		return parseTime(time, option);
	} else {
		return d.getMonth() + 1 + "月" + d.getDate() + "日" + d.getHours() + "时" + d.getMinutes() + "分";
	}
}
/**
 * 获取上一个月的日期
 */
export function getLastMonth(date: any) {
	const now = new Date(date);
	const year = now.getFullYear();
	const month = now.getMonth() + 1;
	const day = now.getDate();
	const nowMonthDay = new Date(year, month, 0).getDate(); // 当前月的总天数
	let dayK = day < 10 ? "0" + day : day;
	const monthK = month - 1 < 10 ? "0" + (month - 1) : month - 1;
	const lastMonthDay = new Date(year, month - 1, 0).getDate();
	if (month - 1 <= 0) return year - 1 + "-" + 12 + "-" + dayK; // 如果是1月，年数往前推一年
	if (lastMonthDay >= day) return year + "-" + monthK + "-" + dayK;
	if (day < nowMonthDay) {
		// 1个月前所在月的总天数小于现在的天日期
		const lastDay = lastMonthDay - (nowMonthDay - day);
		dayK = lastDay < 10 ? "0" + lastDay : lastDay;
		return year + "-" + monthK + "-" + dayK;
	}
	return year + "-" + monthK + "-" + (lastMonthDay < 10 ? "0" + lastMonthDay : lastMonthDay); // 当前天日期小于当前月总天数
}
/**
 * @param {string} url
 * @returns {Object}
 */
export function getQueryObject(url: any) {
	url = url == null ? window.location.href : url;
	const search = url.substring(url.lastIndexOf("?") + 1);
	const obj: any = {};
	const reg = /([^?&=]+)=([^?&=]*)/g;
	search.replace(reg, (rs: any, $1: any, $2: any) => {
		const name = decodeURIComponent($1);
		let val = decodeURIComponent($2);
		val = String(val);
		obj[name] = val;
		return rs;
	});
	return obj;
}

/**
 * @param {string} input value
 * @returns {number} output value
 */
export function byteLength(str: any) {
	// returns the byte length of an utf8 string
	let s = str.length;
	for (let i = str.length - 1; i >= 0; i--) {
		const code = str.charCodeAt(i);
		if (code > 0x7f && code <= 0x7ff) s++;
		else if (code > 0x7ff && code <= 0xffff) s += 2;
		if (code >= 0xdc00 && code <= 0xdfff) i--;
	}
	return s;
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual: any) {
	const newArray = [];
	for (let i = 0; i < actual.length; i++) {
		if (actual[i]) {
			newArray.push(actual[i]);
		}
	}
	return newArray;
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function param(json: any) {
	if (!json) return "";
	return cleanArray(
		Object.keys(json).map(key => {
			if (json[key] === undefined) return "";
			return encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
		})
	).join("&");
}

/**
 * @param {string} url
 * @returns {Object}
 */
export function param2Obj(url: any) {
	const search = decodeURIComponent(url.split("?")[1]).replace(/\+/g, " ");
	if (!search) {
		return {};
	}
	const obj: any = {};
	const searchArr = search.split("&");
	searchArr.forEach(v => {
		const index = v.indexOf("=");
		if (index !== -1) {
			const name = v.substring(0, index);
			const val = v.substring(index + 1, v.length);
			obj[name] = val;
		}
	});
	return obj;
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val: any) {
	const div = document.createElement("div");
	div.innerHTML = val;
	return div.textContent || div.innerText;
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target: any, source: any) {
	if (typeof target !== "object") {
		target = {};
	}
	if (Array.isArray(source)) {
		return source.slice();
	}
	Object.keys(source).forEach(property => {
		const sourceProperty = source[property];
		if (typeof sourceProperty === "object") {
			target[property] = objectMerge(target[property], sourceProperty);
		} else {
			target[property] = sourceProperty;
		}
	});
	return target;
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element: any, className: any) {
	if (!element || !className) {
		return;
	}
	let classString = element.className;
	const nameIndex = classString.indexOf(className);
	if (nameIndex === -1) {
		classString += "" + className;
	} else {
		classString = classString.substr(0, nameIndex) + classString.substr(nameIndex + className.length);
	}
	element.className = classString;
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type: any) {
	if (type === "start") {
		return new Date().getTime() - 3600 * 1000 * 24 * 90;
	} else {
		return new Date(new Date().toDateString());
	}
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func: any, wait: any, immediate: any) {
	let timeout: any, args: any, context: any, timestamp: any, result: any;

	const later = function () {
		// 据上一次触发时间间隔
		const last = +new Date() - timestamp;

		// 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
		if (last < wait && last > 0) {
			timeout = setTimeout(later, wait - last);
		} else {
			timeout = null;
			// 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
			if (!immediate) {
				result = func.apply(context, args);
				if (!timeout) context = args = null;
			}
		}
	};

	return function (this: any, ...args: any) {
		context = this;
		timestamp = +new Date();
		const callNow = immediate && !timeout;
		// 如果延时不存在，重新设定延时
		if (!timeout) timeout = setTimeout(later, wait);
		if (callNow) {
			result = func.apply(context, args);
			context = args = null;
		}

		return result;
	};
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 * @param {Object} source
 * @returns {Object}
 */
export function deepClone(source: any) {
	if (!source && typeof source !== "object") {
		throw new Error("error arguments");
	}
	const targetObj: any = source.constructor === Array ? [] : {};
	Object.keys(source).forEach(keys => {
		if (source[keys] && typeof source[keys] === "object") {
			targetObj[keys] = deepClone(source[keys]);
		} else {
			targetObj[keys] = source[keys];
		}
	});
	return targetObj;
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr: any) {
	return Array.from(new Set(arr));
}

/**
 * 生成 uuid
 * */
export function generateUUID(): string {
	const cryptoObj = window.crypto || (window as any).msCrypto; // For IE11 compatibility
	if (!cryptoObj) {
		throw new Error("Crypto API not available.");
	}

	const buf = new Uint8Array(16);
	cryptoObj.getRandomValues(buf);

	buf[6] = (buf[6] & 0x0f) | 0x40; // set version to 4 (0100)
	buf[8] = (buf[8] & 0x3f) | 0x80; // set bits 6-7 to 10

	const hexOctets = Array.prototype.map.call(buf, (x: number) => ("00" + x.toString(16)).slice(-2));
	const uuid = `${hexOctets.slice(0, 4).join("")}-${hexOctets.slice(4, 6).join("")}-${hexOctets.slice(6, 8).join("")}-${hexOctets
		.slice(8, 10)
		.join("")}-${hexOctets.slice(10).join("")}`;

	return uuid;
}

/**
 * Check if an element has a class
 * @param {HTMLElement} elm
 * @param {string} cls
 * @returns {boolean}
 */
export function hasClass(ele: any, cls: any) {
	return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
}

/**
 * Add class to element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function addClass(ele: any, cls: any) {
	if (!hasClass(ele, cls)) ele.className += " " + cls;
}

/**
 * Remove class from element
 * @param {HTMLElement} elm
 * @param {string} cls
 */
export function removeClass(ele: any, cls: any) {
	if (hasClass(ele, cls)) {
		const reg = new RegExp("(\\s|^)" + cls + "(\\s|$)");
		ele.className = ele.className.replace(reg, " ");
	}
}

export function makeMap(str: any, expectsLowerCase: any) {
	const map = Object.create(null);
	const list = str.split(",");
	for (let i = 0; i < list.length; i++) {
		map[list[i]] = true;
	}
	return expectsLowerCase ? (val: any) => map[val.toLowerCase()] : (val: any) => map[val];
}

export const exportDefault = "export default ";

export const beautifierConf = {
	html: {
		indent_size: "2",
		indent_char: " ",
		max_preserve_newlines: "-1",
		preserve_newlines: false,
		keep_array_indentation: false,
		break_chained_methods: false,
		indent_scripts: "separate",
		brace_style: "end-expand",
		space_before_conditional: true,
		unescape_strings: false,
		jslint_happy: false,
		end_with_newline: true,
		wrap_line_length: "110",
		indent_inner_html: true,
		comma_first: false,
		e4x: true,
		indent_empty_lines: true
	},
	js: {
		indent_size: "2",
		indent_char: " ",
		max_preserve_newlines: "-1",
		preserve_newlines: false,
		keep_array_indentation: false,
		break_chained_methods: false,
		indent_scripts: "normal",
		brace_style: "end-expand",
		space_before_conditional: true,
		unescape_strings: false,
		jslint_happy: true,
		end_with_newline: true,
		wrap_line_length: "110",
		indent_inner_html: true,
		comma_first: false,
		e4x: true,
		indent_empty_lines: true
	}
};

// 首字母大小
export function titleCase(str: any) {
	return str.replace(/( |^)[a-z]/g, (L: any) => L.toUpperCase());
}

// 下划转驼峰
export function camelCase(str: any) {
	return str.replace(/_[a-z]/g, (str1: any) => str1.substr(-1).toUpperCase());
}

export function isNumberStr(str: any) {
	return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}

export function noSpecialCode(e: any, type: any) {
	// type1：只能输入数字
	// type2：只能输入大写字母和数字
	// type3：只能输入中文字符
	// type4：不能输入中文字符
	// type5：只能# - _ / . 五种字符
	// type6: 只能输入数字，最多保留七位小数
	// type7: 不能含有emoji表情
	// type8: 只支持输入英文、_且必须英文开头
	// type9: 不能输入表情和空格
	// type10: 字母 数字 特殊字符
	// default: 只能输入字母数字和汉字
	let pattern: any = "";
	switch (type) {
		case 1:
			pattern = /[\D]*/g;
			break;
		case 2:
			pattern = /[^A-Z\d]*/g;
			break;
		case 3:
			pattern = /[^\a-\z\A-\Z0-9\u4E00-\u9FA5\.\,\?\。\，\？\、\-\——\=\;\《\》\！\!\(\)\（\）\+\$]/g;
			break;
		case 4:
			pattern = /[\u4e00-\u9fa5]/g;
			break;
		case 5:
			pattern = /[^\a-\z\A-\Z0-9\u4E00-\u9FA5\#\-\_\/\.]/g;
			break;
		case 7:
			pattern =
				/[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2159]|[\u2180-\u2210]|[\u221b-\u2712]|[\u2720-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/gi;
			break;
		case 8:
			pattern = /[^a-zA-Z_]|^[^a-zA-Z]/g;
			break;
		case 9:
			pattern =
				/\s|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF][\u200D|\uFE0F]|[\uD83C|\uD83D|\uD83E][\uDC00-\uDFFF]|[0-9|*|#]\uFE0F\u20E3|[0-9|#]\u20E3|[\u203C-\u3299]\uFE0F\u200D|[\u203C-\u3299]\uFE0F|[\u2122-\u2159]|[\u2180-\u2210]|[\u221b-\u2712]|[\u2720-\u2B55]|\u303D|[\A9|\AE]\u3030|\uA9|\uAE|\u3030/g;
			break;
		case 10:
			pattern = /[^\a-\z\A-\Z0-9\!\@\#\$\%\^\&\*\?\(\)\=\+\_\-\~\`\{\}\[\]\|\\\:\;\"\'\<\>\/\.\,\/]/g;
			break;
		default:
			pattern = /[^0-9A-Za-z\u4e00-\u9fa5]*/g;
			break;
	}
	if (type == 6) {
		//先把非数字的都替换掉，除了数字和.
		e = e.replace(/[^\d.]/g, "");
		//保证只有出现一个.而没有多个.
		e = e.replace(/\.{2,}/g, ".");
		//必须保证第一个为数字而不是.
		e = e.replace(/^\./g, "");
		//保证.只出现一次，而不能出现两次以上
		e = e.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
		//最多保留七位小数
		e = e.replace(/^(\-)*(\d+)\.(\d{7}).*$/, "$1$2.$3");
		return e;
	}
	return e.replace(pattern, "");
}

// 数组转树
/**
 * @description 测点数组转树
 * @param {Array} data
 * @returns 位置-测点树
 * */
export function groupDataIntoTree(data: any[]) {
	const resultMap = new Map();

	for (const item of data) {
		if (!resultMap.has(item.locationCode)) {
			resultMap.set(item.locationCode, {
				code: item.locationCode,
				name: item.locationName || item.locationCodeName,
				children: []
			});
		}
		resultMap.get(item.locationCode).children.push({
			code: item.pointCode,
			name: item.pointName || item.pointCodeName
		});
	}

	return [...resultMap.values()];
}

/**
 * @description 数组对象去重
 * @param { Array } source 源数组
 * @param { String | Number } key 去重的唯一key值
 * @returns { Array } 去重后的数组
 * */
export function removeRepeat<T>(source: T[], key: string | number) {
	let map = new Map();
	let target = [];
	for (const value of source) {
		if (!map.has(value[key])) {
			map.set(value[key], true);
			target.push(value);
		}
	}
	return target;
}

/**
 * 下载地址资源到本地
 * @param {String} url
 * @param {String} filename
 */
export function exportFileForUrl(url: string, filename: string = "") {
	console.log(url, filename);
	if (!url) {
		return;
	}
	const a = document.createElement("a");
	a.href = url;
	a.download = filename;
	a.click();
	window.URL.revokeObjectURL(url);
}
